package cn.remex.core.util.date;

import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Assert;
import cn.remex.core.util.Judgment;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;


public class DateHelper {

    private final static String formatDefault = "yyyy-MM-dd HH:mm:ss";

    /*
     * 万能的日期转化
     * Created by guoqi on 2016/6/27.
     */
    public static LocalDateTime parse(String dateTimeStr) {
        LocalDateTime localDateTime = null;
        //先匹配日期时间
        for (DateTimeFormatter dateTimeFormatter : DateFomatters.dateTimeFormatterList) {
            if (Judgment.nullOrBlank(localDateTime)) {
                try {
                    localDateTime = LocalDateTime.parse(dateTimeStr, dateTimeFormatter);
                } catch (Exception ignored) {
                }
            } else {
                break;
            }
        }
        //再匹配日期
        for (DateTimeFormatter dateTimeFormatter : DateFomatters.dateFormattersList) {
            if (Judgment.nullOrBlank(localDateTime)) {
                try {
                    localDateTime = LocalDate.parse(dateTimeStr, dateTimeFormatter).atStartOfDay();
                } catch (Exception ignored) {
                }
            } else {
                break;
            }
        }
        Assert.notNull(localDateTime, ServiceCode.FAIL, "时间格式错误,不符合默认的几个格式，请自己格式化");
        return localDateTime;
    }

    /*
     *  获取当前时间字符串
     *      返回一个格式为 yyyy-MM-dd HH:mm:ss
     */
    public static String getNow(String... format) {
        LocalDateTime localDateTime = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format == null || format.length < 1 ? formatDefault : format[0]);
        return localDateTime.format(dateTimeFormatter);

    }

    /*
     * 格式化 localdate
     *      默认返回 yyyy-MM-dd
     */
    public static String formatDate(LocalDate localDate, String... format) {
        if (null == format || format.length < 1)
            return localDate.toString();
        else {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format[0]);
            return localDate.format(dateTimeFormatter);
        }
    }
    /*
     * 格式化 localdate
     *      默认返回 yyyy-MM-dd
     */
    public static Date formatDate(String dateStr, String format) {
        Date date = null;
        try {
            date = new SimpleDateFormat(format).parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /*
     * 格式化 localdateTime
     */
    public static String formatDate(LocalDateTime localDateTime, String... format) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(null == format || format.length < 1 ? formatDefault : format[0]);
        return localDateTime.format(dateTimeFormatter);
    }

    /**
     * date 转化为 LocalDateTime
     *
     * @param date 被转化的date
     * @return 返回转化后的 日期
     * @
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /*
     *  date 转化为LocalDate
     *  java.util.Date --&gt; java.time.LocalDate
     */
    public static LocalDate dateToLocalDate(Date date) {
        return dateToLocalDateTime(date).toLocalDate();
    }


    /**
     * localdate 转化为 date
     *
     * @param localDate 被转化的日期
     * @return 转化后的date
     */
    public static Date localDateToDate(LocalDate localDate) {
        Assert.notNull(localDate, ServiceCode.FAIL, "转换时间为空！");
        Instant instant = localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    /**
     * localDateTime 转化为 date
     *
     * @param localDateTime 被转化的 日期
     * @return 返回date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        Assert.notNull(localDateTime, ServiceCode.FAIL, "转换时间为空！");
        Instant instants = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instants);
    }

    /**
     * 计算距今为止的 几分钟后的时间
     *
     * @param minute
     * @return
     */
    public static Date getDateByAddMinute(int minute) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MINUTE, minute);
        return c.getTime();
    }
    /**
     * 计算距今为止的 几个月后的时间
     *
     * @param month
     * @return
     */
    public static Date getDateByAddMonth(int month) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, month);
        return c.getTime();
    }

    /**
     * 计算距date为止的 几个月后的时间
     *
     * @param month
     * @return
     */
    public static Date getDateByAddMonth(Date date, int month) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MONTH, month);
        return c.getTime();
    }

    /**
     * 计算距date为止的 几天后的时间
     *
     * @param day
     * @return
     */
    public static Date getDateByAddDay(Date date, int day) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, day);
        return c.getTime();
    }
    /**
     * 取日期的 00:00:00
     * @param date
     * @return
     */
    public static Date getDayStart(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(formatDate(formatDate(date, "yyyy-MM-dd"), "yyyy-MM-dd"));
        return c.getTime();
    }
    /**
     * 取日期的 23:59:59
     * @param date
     * @return
     */
    public static Date getDayEnd(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(formatDate(formatDate(date, "yyyy-MM-dd 23:59:59"), formatDefault));
        return c.getTime();
    }
    /**
     * 取日期的 00:00:00
     * @param date
     * @return
     */
    public static Date getDayStart(String date) {
        Calendar c = Calendar.getInstance();
        c.setTime(formatDate(date, "yyyy-MM-dd"));
        return c.getTime();
    }
    /**
     * 取日期的 23:59:59
     * @param date
     * @return
     */
    public static Date getDayEnd(String date) {
        Calendar c = Calendar.getInstance();
        c.setTime(formatDate(date, "yyyy-MM-dd"));
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        return c.getTime();
    }
    public static Date getDateByAddDay(String date, int day) {
        Calendar c = Calendar.getInstance();
        c.setTime(formatDate(date, "yyyy-MM-dd"));
        c.add(Calendar.DAY_OF_MONTH, day);
        return c.getTime();
    }

    /**
     * 计算距今为止的 几天前或几天后的时间
     *
     * @param days
     * @return
     */
    public static Date getDateByDay(int days) {
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(c.DATE, days);
        return c.getTime();
    }

    /**
     * 获取date后的month个月的时间
     *
     * @param date
     * @param month
     * @return
     */
    public static List<Date> getDateListByMonth(Date date, int month) {
        List<Date> list = new ArrayList<>();
        for (int i = 1; i <= month; i++) {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.add(c.MONTH, i);
            if (i == month) c.add(c.DATE, -1);
            list.add(c.getTime());
        }
        return list;
    }
    /**
     * 获取date后的month个月前当月的第一天的时间
     *
     * @param date
     * @return
     */
    public static Date getStartDayByMonth(String date, int months) {
        return DateHelper.localDateTimeToDate(parse(date).minusMonths(months).with(TemporalAdjusters.firstDayOfMonth()).toLocalDate().atStartOfDay());
    }

    /**
     * 获取date后的month个月前的时间
     *
     * @param date
     * @param month
     * @return
     */
    public static List<Date> getDateListBySubMonth(Date date, int month) {
        List<Date> list = new ArrayList<>();
        for (int i = 1; i <= month; i++) {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.add(c.MONTH, -i);
            if (i == month) c.add(c.DATE, 1);
            list.add(c.getTime());
        }
        return list;
    }

    /**
     * 获取date后的month个月前的时间(包括date所在月份)
     *
     * @param date
     * @param month
     * @return
     */
    public static List<String> getDateListStrBySubMonth(Date date, int month) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < month; i++) {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            c.add(c.MONTH, -i);
            if (i == month) c.add(c.DATE, 1);
            list.add(formatDate(c.getTime(), "yyyy-MM"));
        }
        return list;
    }

    /**
     * 获取date的日期几号
     *
     * @param date
     * @return
     */
    public static int getDayByDate(Date date) {

        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(Calendar.DAY_OF_MONTH);

    }

    public static String formatDate(Date date, String format) {
        if (date != null && format != null) {
            DateFormat f = new SimpleDateFormat(format);
            return f.format(date);
        }
        return null;
    }

    public static String getDateTimeToString() {
        LocalDateTime arrivalDate = LocalDateTime.now();
        String landing = "";
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMddhhmmss");
        landing = arrivalDate.format(format);
        return landing;
    }

    /**
     * 计算两个时间的月份差
     * @param minDate
     * @param maxDate
     * @return
     */
    public static int getDiffMonth(String minDate, String maxDate){
        int result = 0;

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();

        try {
            min.setTime(sdf.parse(minDate));
            max.setTime(sdf.parse(maxDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        int months = max.get(Calendar.MONTH) - min.get(Calendar.MONTH);
        int years = (max.get(Calendar.YEAR) - min.get(Calendar.YEAR)) * 12;
        int days = max.get(Calendar.DAY_OF_MONTH) - min.get(Calendar.DAY_OF_MONTH);

        result = months + years;
        if(days < 0){
            result = result - 1;
        }
        return result;
    }
    /**
     * 计算两个时间的月份差
     * @param minDate
     * @param maxDate
     * @return
     */
    public static int getDiffMonth(Date minDate, Date maxDate){
        int result = 0;
        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();

        min.setTime(minDate);
        max.setTime(maxDate);

        int months = max.get(Calendar.MONTH) - min.get(Calendar.MONTH);
        int years = (max.get(Calendar.YEAR) - min.get(Calendar.YEAR)) * 12;
        int days = max.get(Calendar.DAY_OF_MONTH) - min.get(Calendar.DAY_OF_MONTH);

        result = months + years;
        if(days < 0){
            result = result - 1;
        }
        return result;
    }
    /**
     * 计算两个时间的天数差
     * @param minDate
     * @param maxDate
     * @return
     */
    public static int getDiffDays(Date minDate, Date maxDate){
        Calendar cal = Calendar.getInstance();
        cal.setTime(minDate);
        long time1 = cal.getTimeInMillis();
        cal.setTime(maxDate);
        long time2 = cal.getTimeInMillis();
        long between_days = (time2-time1)/(1000*3600*24);

        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 计算两个时间的天数差
     *  不管够不够一天，都算一天
     * @param minDate
     * @param maxDate
     * @return
     */
    public static int getDiffDaysByDay(Date minDate, Date maxDate){
        Calendar minCal = Calendar.getInstance();
        Calendar maxCal = Calendar.getInstance();
        minDate = formatDate(formatDate(minDate, "yyyy-MM-dd"), "yyyy-MM-dd");
        maxDate = formatDate(formatDate(maxDate, "yyyy-MM-dd"), "yyyy-MM-dd");
        minCal.setTime(minDate);
        long time1 = minCal.getTimeInMillis();
        maxCal.setTime(maxDate);
        long time2 = maxCal.getTimeInMillis();
        long between_days = (time2-time1)/(1000*3600*24);

        return Integer.parseInt(String.valueOf(between_days));
    }
    /**
     * date1 是否小于等于 date2 只计算到天
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isLeDate(Date date1, Date date2){
        if(date1==null || date2==null){
            return false;
        }
        Date tDate1 = formatDate(formatDate(date1,"yyyy-MM-dd"),"yyyy-MM-dd");
        Date tDate2 = formatDate(formatDate(date2,"yyyy-MM-dd"),"yyyy-MM-dd");

        return tDate1.getTime() - tDate2.getTime()<=0;
    }
    public static boolean isLtDate(Date date1, Date date2){
        if(date1==null || date2==null){
            return false;
        }
        Date tDate1 = formatDate(formatDate(date1,"yyyy-MM-dd"),"yyyy-MM-dd");
        Date tDate2 = formatDate(formatDate(date2,"yyyy-MM-dd"),"yyyy-MM-dd");

        return tDate1.getTime() - tDate2.getTime()<0;
    }

    /**
     * date1 是否大于等于 date2 只计算到天
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isGeDate(Date date1, Date date2){
        if(date1==null || date2==null){
            return false;
        }
        Date tDate1 = formatDate(formatDate(date1,"yyyy-MM-dd"),"yyyy-MM-dd");
        Date tDate2 = formatDate(formatDate(date2,"yyyy-MM-dd"),"yyyy-MM-dd");
        return tDate1.getTime() - tDate2.getTime()>=0;
    }
    public static boolean isGtDate(Date date1, Date date2){
        if(date1==null || date2==null){
            return false;
        }
        Date tDate1 = formatDate(formatDate(date1,"yyyy-MM-dd"),"yyyy-MM-dd");
        Date tDate2 = formatDate(formatDate(date2,"yyyy-MM-dd"),"yyyy-MM-dd");
        return tDate1.getTime() - tDate2.getTime()>0;
    }


    /**
     * 计算距离今天 几个月
     * @param minDate
     * @return
     */
    public static int getDiffMonth(String minDate){
        return getDiffMonth(minDate, getNow());
    }
    /**
     * 计算距离今天 几个月
     * @param minDate
     * @return
     */
    public static int getDiffMonth(Date minDate){
        return getDiffMonth(minDate, new Date());
    }

    //当前系统时间的月份的第一天
    public static String getFirstDayOfCurrentMonth(){
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(calendar.getTime());
    }

    //当前时间的月份的第一天
    public static String getFirstDayOfDate(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(calendar.getTime());
    }

    //取某月的开始时间
    public static String getStartTimeOfDayStr(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        SimpleDateFormat format = new SimpleDateFormat(formatDefault);
        return format.format(calendar.getTime());
    }
    //取某月的开始时间
    public static Date getMonthStartDate(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        return calendar.getTime();
    }
    //取某月的结束时间
    public static Date getMonthEndDate(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    public static Date getDateAddDay(Date date,int day){
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, day);// 今天+1天
        Date tomorrow = c.getTime();
//        return f.format(tomorrow);
        return  c.getTime();
    }
    public static void main(String[] args) {
        Date date1 = new Date(2017,5,10,10,24);
        Date date2 = new Date(2017,5,11,10,28);
        System.out.println(isLeDate(date1,date2));
        System.out.println(isGeDate(date1,date2));
        System.out.println(isLtDate(date1,date2));
        System.out.println(isGtDate(date1,date2));
    }

    public static boolean isValidDate(String dateStr,String pattern){

        boolean convertSuccess=true;
        //指定日期格式为四位年/两位月份/两位日期，注意yyyy/MM/dd区分大小写
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            //设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期
            format.setLenient(false);
            format.parse(dateStr);
        } catch (ParseException e) {
            // e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess=false;
        }
        return convertSuccess;
    }

}
